
package xib.core;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Properties;
import xib.Page;
import xib.Panel;
import xib.parserTools.adaptee.AdapteeParserDOM;
import xib.parserTools.adaptee.AdapteeParserSax;
import xib.parserTools.adaptee.AdapteeType;
import xib.parserTools.interfaces.IAdapterParser;
import xib.utils.XibException;

/**
 *
 * @author xavierds
 */
public final class XibController {

    /**
     * Attribute with the complete name of the file
     */
    private String filePathname;

    /**
     * Attribute with the complete name of the configuration file
     * for the adaptee.
     */
    private String adapterPropertiesPathname = "adapter.properties";
    
    
    private ArrayList<Integer> chaptersNumbers;

    /**
     * Attributes to know where we are located in the xib.
     */
    private int chapterNumber, chapterPosition, pagePosition, panelOrder;

    private int quantityOfChapters, quantityOfPages, quantityOfPanels;

    private FileHandler fileHandler;

    private LastFunction lastFunction;

    /**
     * Attributes with the core.
     */
    private Xib xib;

    /**
     * Default Constructor setting the default pathname.
     * Configuration file is adapter.properties in the ./
     */
    public XibController(){
        chapterNumber = 0;
        pagePosition = 0;
        panelOrder = 0;
        xib = null;
    }

    /**
     * Set the pathname for the configuration file of the adaptee.
     * @param pathname
     */
    public void setFileAdapterProperties(String pathname){
        this.adapterPropertiesPathname  = pathname;
    }

    /**
     * Load the file in the Controller. The steps are:
     * 1.Initialize the adaptee from the configuration file, if it isn't set
     * properly it load the ParserDOM.
     * 2. Initialize the adaptee.
     * 3. Initialize the xib and the relative information in the Controller.
     * @param pathname
     */
    public void loadFile(String pathname)throws IOException{

        this.filePathname = pathname;
        fileHandler = new FileHandler(filePathname);

        //Load adaptee
        IAdapterParser adaptee = getAdaptee();

        //Initialize the xib
        xib = new Xib(adaptee);
        xib.loadInputStream(fileHandler.getEntry("xib.xml"));

        //Set the default values
        chaptersNumbers = xib.getChaptersNumbers();
        quantityOfChapters = chaptersNumbers.size();
        quantityOfPages = xib.getTotalPagesOfChapter(chaptersNumbers.get(0));

        chapterNumber = chaptersNumbers.get(0);
        chapterPosition = 0;
        pagePosition = 0;
        panelOrder = 0;
        lastFunction = LastFunction.Default;
    }

    private IAdapterParser getAdaptee(){
        AdapteeType adapteeType;
        IAdapterParser adaptee = null;
        //Set the Adaptee we are going to use to load the file
        try{
            Properties props = new Properties();
            props.load(fileHandler.getEntry(adapterPropertiesPathname));
            adapteeType = AdapteeType.valueOf(props.getProperty("adaptee"));

            if(adapteeType.equals(AdapteeType.ParserDOM))
                adaptee = new AdapteeParserDOM();

            if(adapteeType.equals(AdapteeType.ParserSAX))
                adaptee = new AdapteeParserSax();

            if(adaptee == null)
                adaptee = new AdapteeParserDOM();
        }
        catch(Exception ex){
            adaptee = new AdapteeParserDOM();
        }
        return adaptee;
    }

    public ArrayList<String> getAvailablesLanguages(){
        return xib.getAvailablesLanguages();
    }

    public String getDefaultLanguage(){
        return xib.getDefaultLanguage();
    }

    public String getOriginalLanguage(){
        return xib.getOriginalLanguage();
    }

    public int getTotalPages(){
        isInitialized();
        return xib.getTotalPages();
    }

    public int getTotalPanels(){
        isInitialized();
        return xib.getTotalPanels();
    }

    public ArrayList<Integer> getChaptersNumbers(){
       isInitialized();
       return xib.getChaptersNumbers();
    }

    public int getNumPagesOfChapter(int chapterNumber){
        isInitialized();
        return xib.getTotalPagesOfChapter(chapterNumber);
    }



    

    public Page getNextPage(){
        isInitialized();
        nextPage();
        lastFunction = LastFunction.Page;
        Page page = xib.getPageAt(chapterNumber, pagePosition);
        for(int i=1; i <= quantityOfPanels; i++)
            ((PanelXib)page.getPanel(i)).setInputStream(fileHandler);
        return page;
    }

    public Page getPreviousPage(){
        isInitialized();
        previousPage();
        lastFunction = LastFunction.Page;
        Page page = xib.getPageAt(chapterNumber, pagePosition);
        for(int i=1; i <= quantityOfPanels; i++)
            ((PanelXib)page.getPanel(i)).setInputStream(fileHandler);
        return page;
    }

    public Page getPageAt(int chapterNumber, int pagePosition){
        isInitialized();
        lastFunction = LastFunction.Page;
        Page res = xib.getPageAt(chapterNumber, pagePosition);
        this.chapterNumber = chapterNumber;
        this.chapterPosition = getChapterPosition(chapterNumber);
        this.pagePosition = pagePosition;
        this.panelOrder = 1;
        quantityOfPages = xib.getTotalPagesOfChapter(chapterNumber);
        quantityOfPanels = res.getQuantityOfPanels();
        for(int i=1; i <= quantityOfPanels; i++)
            ((PanelXib)res.getPanel(i)).setInputStream(fileHandler);
        return res;
    }

    public Page getPageAt(int page){
        isInitialized();
        lastFunction = LastFunction.Page;
        Page res = xib.getPageAt(page);
        int[] aux = xib.foundChapterAsPage(page);
        chapterNumber = xib.getChaptersNumbers().get(aux[0]);
        pagePosition = aux[1];
        panelOrder = 1;
        quantityOfPages = xib.getTotalPagesOfChapter(chapterNumber);
        quantityOfPanels = res.getQuantityOfPanels();
        for(int i=1; i <= quantityOfPanels; i++)
            ((PanelXib)res.getPanel(i)).setInputStream(fileHandler);
        return res;
    }


    public Panel getNextPanel(){
        isInitialized();
        nextPanel();
        lastFunction = LastFunction.Panel;
        PanelXib res = xib.getPanelAt(chapterNumber, pagePosition, panelOrder);
        res.setInputStream(fileHandler);
        return res;
    }

    public Panel getPreviousPanel(){
        isInitialized();
        previousPanel();
        lastFunction = LastFunction.Panel;
        PanelXib res = xib.getPanelAt(chapterNumber, pagePosition, panelOrder);
        res.setInputStream(fileHandler);
        return res;
    }

    public Panel getPanelAt(int chapterNumber, int page, int panelOrder){
        isInitialized();
        lastFunction = LastFunction.Panel;
        PanelXib res = xib.getPanelAt(chapterNumber, page, panelOrder);
        res.setInputStream(fileHandler);
        this.chapterNumber = chapterNumber;
        this.pagePosition = page;
        this.panelOrder = panelOrder;
        return res;
    }

    public Panel getPanelAt(int page, int panelOrder){
        isInitialized();
        lastFunction = LastFunction.Panel;
        PanelXib res = xib.getPanelAt(page, panelOrder);
        res.setInputStream(fileHandler);
        int[] aux = xib.foundChapterAsPage(page);
        this.chapterNumber = xib.getChaptersNumbers().get(aux[0]);
        this.pagePosition = aux[1];
        this.panelOrder = panelOrder;
        return res;
    }

    private void isInitialized(){
        if(xib == null){
            throw new IllegalStateException("No file was loaded");
        }
    }

    
    private boolean nextChapter(){
        if(chapterPosition < quantityOfChapters){
            chapterPosition++;
            chapterNumber = chaptersNumbers.get(chapterPosition);
            quantityOfPages = xib.getTotalPagesOfChapter(chapterNumber);
            panelOrder = 1;
            pagePosition = 1;
            quantityOfPanels = xib.getPageAt(chapterNumber, pagePosition).getQuantityOfPanels();
            return true;
        }
        else{
            return false;
        }
    }

    private boolean nextPage(){
        if(pagePosition < quantityOfPages){
            panelOrder = 1;
            pagePosition++;
            quantityOfPanels = xib.getPageAt(chapterNumber, pagePosition).getQuantityOfPanels();
            return true;
        }
        else{
            return nextChapter();
        }
    }

    private boolean nextPanel(){
        panelOrder++;
        if(panelOrder > quantityOfPanels || lastFunction.equals(LastFunction.Page))
            return nextPage();
        return true;

        /*if(panelOrder < quantityOfPanels){
            panelOrder++;
            return true;
        }
        else{
            return nextPage();
        }*/
    }

    private boolean previousChapter(){
        if(chapterPosition > 0){
            chapterPosition--;
            chapterNumber = chaptersNumbers.get(chapterPosition);
            quantityOfPages = xib.getTotalPagesOfChapter(chapterNumber);
            panelOrder = 1;
            pagePosition = 1;
            quantityOfPanels = xib.getPageAt(chapterNumber, pagePosition).getQuantityOfPanels();
            return true;
        }
        else{
            return false;
        }
    }

    private boolean previousPage(){
        if(pagePosition > 1){
            panelOrder = 1;
            pagePosition--;
            quantityOfPanels = xib.getPageAt(chapterNumber, pagePosition).getQuantityOfPanels();
            return true;
        }
        else
            return previousChapter();
    }

    private boolean previousPanel(){
        panelOrder--;
        if(panelOrder <= 0 || lastFunction.equals(LastFunction.Page))
            return previousPage();
        return true;        
        /*if(panelOrder > 1){
            panelOrder--;
            return true;
        }
        else{
            return previousPage();
        }*/
    }

    private int getChapterPosition(int chapterNumber){
        int res;
        for(res=0; res < chaptersNumbers.size(); res++)
            if(chapterNumber == chaptersNumbers.get(res))
                break;
        return res;
    }

    private enum LastFunction{Default, Page, Panel};

                                
}
